package com.copro.chemdb.subject;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.ihelpuoo.db.sql.SQLSegment;

import com.copro.chemdb.constants.ConstTypeUtils;
import com.copro.chemdb.subject.opt.Option;
import com.copro.simple.Application;
import com.copro.simple.SimpleException;
import com.copro.simple.db.QueryCallback;

public class SubjectUtils {

	/**
	 * Provide the query function for list
	 * 
	 * @author zozoh
	 * 
	 */
	static class OptionsGetter implements QueryCallback {

		private List<Option> list;

		public OptionsGetter(List<Option> list) {
			this.list = list;
		}

		public List<Option> getList() {
			return this.list;
		}

		@Override
		public void exec(ResultSet rs) throws SQLException {
			while (rs.next()) {
				list.add(new Option(rs));
			}
		}
	}

	/**
	 * Provide the query function for list
	 * 
	 * @author zozoh
	 * 
	 */
	static class ListGetter implements QueryCallback {

		private List<Subject> list;

		public ListGetter(List<Subject> list) {
			this.list = list;
		}

		public List<Subject> getList() {
			return this.list;
		}

		@Override
		public void exec(ResultSet rs) throws SQLException {
			while (rs.next()) {
				list.add(new Subject(rs));
			}
		}
	}

	/**
	 * Provide the query function for one object
	 * 
	 * @author zozoh
	 * 
	 */
	static class SubjectDetailGetter implements QueryCallback {

		private Subject subject;

		SubjectDetailGetter() {
			this.subject = new Subject();
		}

		public Subject getObject() {
			return this.subject;
		}

		@Override
		public void exec(ResultSet rs) throws SQLException {
			if (rs.first())
				this.subject = new Subject(rs);
		}

	}

	@Deprecated
	public static List<Subject> queryChildrenSubjects(Application app,
			Subject subject) throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = subject.getId() > 0 ? app.getSQL("childSubject") : app
				.getSQL("rootSubject");
		sql.set("id", subject.getId());
		sql.set("quesId", subject.getQuesId());
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> queryChildrenSubjects(Application app,
			Subject subject, int statType) throws SimpleException {
		if (0 == statType) {
			return queryChildrenQuesSubjects(app, subject);
		} else {
			return queryChildrenDBSubjects(app, subject);
		}
	}

	public static List<Subject> queryChildrenDBSubjects(Application app,
			Subject subject) throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = subject.getId() > 0 ? app.getSQL("childDBSubject")
				: app.getSQL("rootDBSubject");
		sql.set("id", subject.getId());
		sql.set("quesId", subject.getQuesId());
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> queryChildrenQuesSubjects(Application app,
			Subject subject) throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = subject.getId() > 0 ? app.getSQL("childQuesSubject")
				: app.getSQL("rootQuesSubject");
		sql.set("id", subject.getId());
		sql.set("quesId", subject.getQuesId());
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> listCanQuerySubjects(Application app, int quesId)
			throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = app.getSQL("canQuerySubject");
		sql.set("quesId", quesId);
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> queryAllSubjectsExcept(Application app, int id)
			throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = app.getSQL("allSubjectExcept");
		sql.set("id", id);
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> queryAllSubjects(Application app, int quesId)
			throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = app.getSQL("listSubject");
		sql.set("quesId", quesId);
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	@Deprecated
	public static List<Subject> queryRootSubjects(Application app, int quesId)
			throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = app.getSQL("rootSubject");
		sql.set("quesId", quesId);
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> queryRootSubjects(Application app, int quesId,
			int statType) throws SimpleException {
		if (0 == statType) {
			return queryRootQuesSubjects(app, quesId);
		} else {
			return queryRootDBSubjects(app, quesId);
		}
	}

	public static List<Subject> queryRootDBSubjects(Application app, int quesId)
			throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = app.getSQL("rootDBSubject");
		sql.set("quesId", quesId);
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> queryRootQuesSubjects(Application app,
			int quesId) throws SimpleException {
		ListGetter callback = new ListGetter(new LinkedList<Subject>());
		SQLSegment sql = app.getSQL("rootQuesSubject");
		sql.set("quesId", quesId);
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	public static List<Subject> queryStatSubjects(Application app, int quesId)
			throws SimpleException {
		List<Subject> re = new LinkedList<Subject>();

		List<Subject> list = SubjectUtils.queryRootSubjects(app, quesId);
		Iterator<Subject> it = list.iterator();
		while (it.hasNext()) {
			Subject subject = it.next();
			if (subject.isCanStat()) {
				re.add(subject);
			} else {
				re.addAll(fetchSubStatSubjects(app, subject));
			}
		}
		return re;
	}

	private static List<Subject> fetchSubStatSubjects(Application app,
			Subject subject) throws SimpleException {
		List<Subject> re = new LinkedList<Subject>();

		List<Subject> list = SubjectUtils.queryChildrenSubjects(app, subject);
		Iterator<Subject> it = list.iterator();
		while (it.hasNext()) {
			Subject sub = it.next();
			if (sub.isCanStat()) {
				re.add(sub);
			} else {
				re.addAll(fetchSubStatSubjects(app, sub));
			}
		}
		return re;
	}

	public static Subject get(Application app, Subject subject)
			throws SimpleException {
		SQLSegment sql = app.getSQL("getSubject");
		sql.set("id", subject.getId());
		sql.set("quesId", subject.getQuesId());
		SubjectDetailGetter callback = new SubjectDetailGetter();
		app.query(sql.toString(), callback);
		callback.getObject().setQuesId(subject.getQuesId());
		return callback.getObject();
	}

	public static void setupVars(HttpServletRequest request, Application app,
			Subject subject) throws SimpleException {
		subject.setOptions(SubjectUtils.queryOptions(app, subject));
		request.setAttribute("subject", subject);
		request.setAttribute("consts", ConstTypeUtils.getConstTypeAll(app));
		request.setAttribute("subjectTypes", app.getSubjectTypes());
		request.setAttribute("rules", app.getStatRuleNames());
		request.setAttribute("allSubjects", SubjectUtils
				.queryAllSubjectsExcept(app, subject.getId()));
	}

	public static List<Option> queryOptions(Application app, Subject subject)
			throws SimpleException {
		OptionsGetter callback = new OptionsGetter(new LinkedList<Option>());
		SQLSegment sql = app.getSQL("queryOptions");
		sql.set("subjectId", subject.getId());
		app.query(sql.toString(), callback);
		return callback.getList();
	}

	/**
	 * Provide the query function for one object
	 * 
	 * @author zozoh
	 * 
	 */
	static class OptionDetailGetter implements QueryCallback {

		private Option option;

		OptionDetailGetter() {
			this.option = new Option();
		}

		public Option getObject() {
			return this.option;
		}

		@Override
		public void exec(ResultSet rs) throws SQLException {
			if (rs.first())
				this.option = new Option(rs);
		}

	}

	public static Option getOption(Application app, int subjectId, int optionId)
			throws SimpleException {
		SQLSegment sql = app.getSQL("getOption");
		sql.set("subjectId", subjectId);
		sql.set("optionId", optionId);
		OptionDetailGetter callback = new OptionDetailGetter();
		app.query(sql.toString(), callback);
		return callback.getObject();
	}
}
